import { GLTFLoader, GLTFParser } from 'three/examples/jsm/loaders/GLTFLoader';
import { AnimationClip, Audio, AudioListener, AudioLoader, Camera, CubeTexture, CubeTextureLoader, FileLoader, Group, Loader, LoadingManager, Texture, TextureLoader, VideoTexture } from 'three';
import { HDRCubeTextureLoader } from 'three/examples/jsm/loaders/HDRCubeTextureLoader';
import { ILoose } from 'three-lib/tool/utils';


/**
 * 资源任务信息类型
 * @param GLTF_MESH 网格模型（glb）
 * @param TEXTURE 纹理贴图（jpg，png）
 * @param CUBE_TEXTURE 立体纹理贴图（盒型，jpg，png）
 * @param HDR_CUBE_TEXTURE hdr立体纹理贴图（hdr）
 * @param AUDIO 音频（mp3）
 * @param VIDEO 视频（mp4）
 * @param DATA 数据（json、xml等）
 */
enum TASK_INFO_TYPES {
    GLTF_MESH,
    TEXTURE,
    CUBE_TEXTURE,
    HDR_CUBE_TEXTURE,
    AUDIO,
    VIDEO,
    DATA,
};


abstract class AbstractAssetTaskInfo<P, T> {

    public abstract type: number;

    public readonly rawInfo: P;

    protected loader: Loader | null;

    public data: T | null = null;

    constructor(info: P) {
        this.rawInfo = info;
        this.loader = this.initializeLoader();
    }

    public abstract verify(url: string): boolean;

    public start(manager: LoadingManager): void {
        if (this.loader) {
            this.loader.manager = manager;
            this.loader.load(this.rawInfo as string, (data) => {
                this.data = this.resolve(data);
            });
        }
    }

    protected abstract initializeLoader(): Loader<any, any> | null;

    protected abstract resolve(data: any): T | null;

}

interface IGLTFMeshAsset {
    animations: Array<AnimationClip>,
    asset: { generator: string, version: string },
    cameras: Array<Camera>,
    parser: GLTFParser,
    scene: Group,
    scenes: Array<Group>,
    userData: ILoose<any>,
}

class GLTFMeshTaskInfo extends AbstractAssetTaskInfo<string, IGLTFMeshAsset> {

    public type: number = TASK_INFO_TYPES.GLTF_MESH;

    public verify(url: string): boolean {
        return url === this.rawInfo;
    }

    protected initializeLoader(): GLTFLoader {
        return new GLTFLoader();
    }

    protected resolve(data: any): IGLTFMeshAsset | null {
        return data;
    }

}

class TextureTaskInfo extends AbstractAssetTaskInfo<string, Texture> {
    public type: number = TASK_INFO_TYPES.TEXTURE;

    public verify(url: string): boolean {
        return url === this.rawInfo;
    }

    protected initializeLoader(): TextureLoader {
        return new TextureLoader();
    }

    protected resolve(data: any): Texture | null {
        return data;
    }
}

class CubeTextureTaskInfo extends AbstractAssetTaskInfo<string[], CubeTexture> {

    public type: number = TASK_INFO_TYPES.CUBE_TEXTURE;

    constructor(px: string, py: string, pz: string, nx: string, ny: string, nz: string) {
        super([px, py, pz, nx, ny, nz]);
    }

    public verify(url: string): boolean {
        return this.rawInfo.includes(url);
    }

    protected initializeLoader(): CubeTextureLoader {
        return new CubeTextureLoader();
    }

    public start(manager: LoadingManager): void {
        if (this.loader) {
            this.loader.manager = manager;
            (this.loader as unknown as CubeTextureLoader).setPath('').load(this.rawInfo, (data) => {
                this.data = this.resolve(data);
            });
        }
    }

    protected resolve(data: any): CubeTexture | null {
        return data;
    }
}

class HDRCubeTextureTaskInfo extends CubeTextureTaskInfo {

    public type: number = TASK_INFO_TYPES.HDR_CUBE_TEXTURE;

    protected initializeLoader(): HDRCubeTextureLoader {
        return new HDRCubeTextureLoader();
    }

    protected resolve(data: any): CubeTexture | null {
        console.log(data);
        return null;
    }
}

class AudioTaskInfo extends AbstractAssetTaskInfo<string, Audio> {

    public type: number = TASK_INFO_TYPES.AUDIO;

    public verify(url: string): boolean {
        return url === this.rawInfo;
    }

    protected initializeLoader(): AudioLoader {
        return new AudioLoader();
    }

    protected resolve(data: any): Audio | null {
        const sound = new Audio(new AudioListener());
        sound.setBuffer(data);
        return sound;
    }
}

class VideoTextureTaskInfo extends AbstractAssetTaskInfo<string, VideoTexture> {

    public type: number = TASK_INFO_TYPES.VIDEO;

    public verify(url: string): boolean {
        return url === this.rawInfo;
    }

    protected initializeLoader(): null {
        return null;
    }

    protected resolve(data: any): VideoTexture | null {
        return null;
    }

    public start(manager: LoadingManager): void {
    }
}

class DataTaskInfo extends AbstractAssetTaskInfo<string, any> {

    public type: number = TASK_INFO_TYPES.DATA;

    public verify(url: string): boolean {
        return url === this.rawInfo;
    }

    protected initializeLoader(): FileLoader | null {
        return new FileLoader();
    }

    protected resolve(data: any): any {
        return data;
    }

}

export {
    GLTFMeshTaskInfo,
    TextureTaskInfo,
    CubeTextureTaskInfo,
    HDRCubeTextureTaskInfo,
    AudioTaskInfo,
    VideoTextureTaskInfo,
    DataTaskInfo,
    TASK_INFO_TYPES,
    AbstractAssetTaskInfo
};
export type {
    IGLTFMeshAsset,
};